package str

import (
	"crypto/aes"
	"crypto/cipher"
	"crypto/md5"
	"encoding/hex"
	"fmt"
	"hash/crc32"
	"hash/crc64"
	"reflect"
	"strconv"
	"strings"
	"unicode/utf8"
)

// Capitalize  字符串首字母转大写
func Capitalize(s string) string {
	var upperStr string
	vv := []rune(s)
	for i := 0; i < len(vv); i++ {
		if i == 0 {
			if vv[i] >= 97 && vv[i] <= 122 { //小写字母的Unicode编码
				vv[i] -= 32 // string的码表相差32位
				upperStr += string(vv[i])
			} else { //首字母非小写字母，直接返回原字符串
				return s
			}
		} else {
			upperStr += string(vv[i])
		}
	}
	return upperStr
}

// SubString 截取字符串，支持中文截取
func SubString(s string, begin, length int) (substr string) {
	// 将字符串的转换成[]rune
	rs := []rune(s)
	lth := len(rs)

	// 简单的越界判断
	if begin < 0 {
		begin = 0
	}
	if begin >= lth {
		begin = lth
	}
	end := begin + length
	if end > lth {
		end = lth
	}

	// 返回子串
	return string(rs[begin:end])
}

// Join 用字符串连接数组元素
func Join(elems interface{}, sep string) string {
	if elems == nil {
		return ""
	}

	if reflect.TypeOf(elems).Kind() != reflect.Array && reflect.TypeOf(elems).Kind() != reflect.Slice {
		//log.Error("the first param must be array or slice")
		return ""
	}

	s := reflect.ValueOf(elems)

	var strElems []string
	strElems = make([]string, s.Len())
	for i := 0; i < s.Len(); i++ {
		strElems[i] = fmt.Sprintf("%v", s.Index(i).Interface())
	}

	return strings.Join(strElems, sep)
}

// 使用一个字符串分割另一个字符串，返回 int 数组
func SplitInt(s, sep string) []int {
	strArr := strings.Split(s, sep)

	ret := make([]int, len(strArr))

	for k, v := range strArr {
		ret[k] = StringToInt(v)
	}

	return ret
}

// 使用一个字符串分割另一个字符串，返回 int 数组
func SplitInt64(s, sep string) []int64 {
	strArr := strings.Split(s, sep)

	ret := make([]int64, len(strArr))

	for k, v := range strArr {
		ret[k] = StringToInt64(v)
	}

	return ret
}

// 使用一个字符串分割另一个字符串，返回 int 数组
func SplitUint16(s, sep string) []uint16 {
	strArr := strings.Split(s, sep)

	ret := make([]uint16, len(strArr))

	for k, v := range strArr {
		ret[k] = StringToUint16(v)
	}

	return ret
}

// 使用一个字符串分割另一个字符串，返回 int 数组
func SplitUint32(s, sep string) []uint32 {
	strArr := strings.Split(s, sep)

	ret := make([]uint32, len(strArr))

	for k, v := range strArr {
		ret[k] = StringToUint32(v)
	}

	return ret
}

// 使用一个字符串分割另一个字符串，返回 int 数组
func SplitUint64(s, sep string) []uint64 {
	strArr := strings.Split(s, sep)

	ret := make([]uint64, len(strArr))

	for k, v := range strArr {
		ret[k] = StringToUint64(v)
	}

	return ret
}

// CRC32 字符串 Crc32
func CRC32(s string) int {
	v := int(crc32.ChecksumIEEE([]byte(s)))
	if v < 0 {
		v = -v
	}

	return v
}

// CRC64 字符串 Crc64
func CRC64(s string) int64 {
	table := crc64.MakeTable(crc64.ECMA)
	v := int64(crc64.Checksum([]byte(s), table))
	if v < 0 {
		v = -v
	}

	return v
}

// MysqlRealEscapeString 数据库字符串字段内容过滤，防止sql注入
func MysqlRealEscapeString(value string) string {
	replace := map[string]string{"\\": "\\\\", "'": `\'`, "\\0": "\\\\0", "\n": "\\n", "\r": "\\r", `"`: `\"`,
		"\x1a": "\\Z"}

	for lodStr, newStr := range replace {
		value = strings.Replace(value, lodStr, newStr, -1)
	}

	return "'" + value + "'"
}

// MysqlRealEscapeStringV2 数据库字符串字段内容过滤，防止sql注入，不自动加单引号
func MysqlRealEscapeStringV2(value string) string {
	replace := map[string]string{"\\": "\\\\", "'": `\'`, "\\0": "\\\\0", "\n": "\\n", "\r": "\\r", `"`: `\"`,
		"\x1a": "\\Z"}

	for lodStr, newStr := range replace {
		value = strings.Replace(value, lodStr, newStr, -1)
	}

	return value
}

// Uint64ToString uint64 -> string
func Uint64ToString(v uint64) string {
	return strconv.FormatUint(v, 10)
}

// Uint32ToString uint32 -> string
func Uint32ToString(v uint32) string {
	return fmt.Sprintf("%d", v)
}

// Uint16ToString uint16 -> string
func Uint16ToString(v uint16) string {
	return fmt.Sprintf("%d", v)
}

// StringToInt string -> int
func StringToInt(v string) int {
	ret, _ := strconv.Atoi(v)
	return ret
}

// StringToInt64 string -> int64
func StringToInt64(v string) int64 {
	ret, _ := strconv.ParseInt(v, 10, 64)
	return ret
}

// StringToUint16 string -> uint16
func StringToUint16(v string) uint16 {
	uintV, _ := strconv.ParseUint(v, 10, 16)
	return uint16(uintV)
}

// StringToUint32 string -> uint32
func StringToUint32(v string) uint32 {
	uintV, _ := strconv.ParseUint(v, 10, 32)
	return uint32(uintV)
}

// StringToUint64 string -> uint64
func StringToUint64(v string) uint64 {
	uintV, _ := strconv.ParseUint(v, 10, 64)
	return uintV
}

// StringUnicodeLen string自负长度
func StringUnicodeLen(v string) int {
	return utf8.RuneCountInString(v)
}

// StringToByte 免拷贝字符串转字节
func StringToByte(s string) (b []byte) {
	return []byte(s)
	//以下实现方式不安全
	//pbytes := (*reflect.SliceHeader)(unsafe.Pointer(&b))
	//pstring := (*reflect.StringHeader)(unsafe.Pointer(&s))
	//pbytes.Data = pstring.Data
	//pbytes.Len = pstring.Len
	//pbytes.Cap = pstring.Len
	//return
}

// ByteToString 免拷贝字节转字符串
func ByteToString(b []byte) (s string) {
	return string(b)
	//以下实现方式不安全
	//pbytes := (*reflect.SliceHeader)(unsafe.Pointer(&b))
	//pstring := (*reflect.StringHeader)(unsafe.Pointer(&s))
	//pstring.Data = pbytes.Data
	//pstring.Len = pbytes.Len
	//return
}

// Uint32ToChar int32 转换为
func Uint32ToChar(v uint32) string {
	return string(rune('A' - 1 + v))
}

// /////////////////////// 下面函数已废弃，请在文档查询使用最新方法，在这里对老版本兼容 ///////////////////////////////
// Md5Value 计算字符串的md5 并转换为字符串
// Deprecated: 已废弃，请使用 crypto.MD5
func Md5Value(s string) string {
	sumBytes := md5.Sum(StringToByte(s))
	return hex.EncodeToString(sumBytes[:])
}

// Md5ValueForByte 计算字符串的md5 并转换为bytes
// Deprecated: 已废弃，请使用 crypto.MD5
func Md5ValueForByte(bs []byte) string {
	sumBytes := md5.Sum(bs)
	return hex.EncodeToString(sumBytes[:])
}

// AesEncryptString Aes加密，key的长度必须是16,24,32位
// Deprecated: 已废弃，请使用 crypto.AesEncrypt
func AesEncryptString(key []byte, msg string) (ret []byte, err error) {
	return AesEncryptByte(key, []byte(msg))
}

// AesEncryptByte Aes加密，key的长度必须是16,24,32位 转换为bytes
// Deprecated: 已废弃，请使用 crypto.AesEncrypt
func AesEncryptByte(key []byte, msg []byte) (ret []byte, err error) {
	var iv = key[:aes.BlockSize]
	encrypted := make([]byte, len(msg))
	aesBlockEncrypter, err := aes.NewCipher(key)
	if err != nil {
		return nil, err
	}
	aesEncrypter := cipher.NewCFBEncrypter(aesBlockEncrypter, iv)
	aesEncrypter.XORKeyStream(encrypted, msg)
	return encrypted, nil
}

// AesDecryptByte Aes解密，key的长度必须是16,24,32位 转换为bytes
// Deprecated: 已废弃，请使用 crypto.AesDecrypt
func AesDecryptByte(key []byte, src []byte) (ret []byte, err error) {
	defer func() {
		//错误处理
		if e := recover(); e != nil {
			err, _ = e.(error)
		}
	}()
	var iv = key[:aes.BlockSize]
	decrypted := make([]byte, len(src))
	var aesBlockDecrypter cipher.Block
	aesBlockDecrypter, err = aes.NewCipher(key)
	if err != nil {
		return nil, err
	}
	aesDecrypter := cipher.NewCFBDecrypter(aesBlockDecrypter, iv)
	aesDecrypter.XORKeyStream(decrypted, src)
	return decrypted, nil
}

// MergeMaps  merge map[string]string
// overwriting duplicate keys
// Deprecated: 已废弃，请使用 mapf.Merge
func MergeMaps(maps ...map[string]string) map[string]string {
	result := make(map[string]string)
	for _, m := range maps {
		for k, v := range m {
			result[k] = v
		}
	}

	return result
}
